/*
 * Created on Feb 2, 2006
 * @author cschaff
 * Copyright Amadeus 2006
 */
package com.amadeus.spin.devtool.soap.shooter.process;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;

import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

import com.amadeus.spin.devtool.soap.shooter.FatalException;
import com.amadeus.spin.devtool.soap.shooter.ProcessInput;
import com.amadeus.spin.devtool.soap.shooter.ProcessOutput;
import com.amadeus.spin.devtool.soap.shooter.config.SoapshooterScenario;
import com.amadeus.spin.standard.util.Dom4jUtils;
import com.amadeus.spin.standard.util.FileUtils;
import com.amadeus.spin.standard.util.XPathHelper;
import com.amadeus.spin.util.soapshooter.Shooter;

/**
 * <p>
 * Created on Feb 2, 2006.
 * </p>
 * <p>
 * 
 * @author cschaff.
 *         </p>
 *         <p>
 *         Copyright Amadeus 2006.
 *         </p>
 * 
 *         TODO Add verbose description here. TODO be more generic, between
 *         ProcessInput and ProcessOutput cases. Ideally, a common abstract
 *         class, with initialization that differs a bit (polymorphism would be
 *         good here).
 */

public class RetrieveHostTraces implements ProcessInput, ProcessOutput {

  public static final String TRACE_DIR_KEY = "tracedir";

  public static final String TRACE_BACKUP_SUBDIR_KEY = "backuptracesubdir";

  public static final String OUTPUT_TRACES_SUBDIR = "hosttraces";

  public static final String A2C_ULTIMATE_SUBDIR = "apiproxy";

  /**
   * When the path specified is too long... the host trace retrieval will not
   * work quite well.
   */
  public static final int MAX_SIZE = 180;

  private static Logger log = Logger.getLogger(RetrieveHostTraces.class);

  private File m_serverLogDir;

  private File m_oldTracesSubdir;

  private File m_traceDestinationDir;

  /**
   * Used to tell if the output file #m_traceDestinationDir is indeed a
   * directory, whose path is not too dangerously long (e.g. 256 chars for a
   * file path seems the maximum allowed - see #MAX_SIZE for our conservative
   * freshold.
   */
  private boolean m_isConfigurationOkay;

  private void init(Node config) {
    m_isConfigurationOkay = true;
    String serverLogPath = XPathHelper.getProperty(config, "@" + TRACE_DIR_KEY);
    m_serverLogDir = new File(serverLogPath);
    if (!m_serverLogDir.isDirectory()) {
      log.error("The weblogic server log directory specified does not exist!!");
      m_isConfigurationOkay = false;
    }
    else {
      String tracesBackupSubdir = XPathHelper.getProperty(config, "@" + TRACE_BACKUP_SUBDIR_KEY);
      m_oldTracesSubdir = new File(serverLogPath + "/" + tracesBackupSubdir);
      if (!m_oldTracesSubdir.exists()) {
        m_oldTracesSubdir.mkdir();
      }
      File apiProxySubdirBackupDir = new File(serverLogPath + "/" + tracesBackupSubdir + "/" + A2C_ULTIMATE_SUBDIR);
      if (!apiProxySubdirBackupDir.exists()) {
        apiProxySubdirBackupDir.mkdir();
      }
      // For output processing: we need another destination dir, out of the
      // server log directory.
      // An extra parameter is thus given in input.
      String outputDirName = XPathHelper.getProperty(config, "@" +
          com.amadeus.spin.devtool.soap.shooter.Shooter.OUTPUT_DIR_NAME_KEY);
      if (outputDirName != null) {
        File outputDir = new File(outputDirName);
        if (!outputDir.isDirectory()) {
          log.error("The output directory specified, '" + outputDirName + "', does not exist!!");
          m_isConfigurationOkay = false;
        }
        else {
          m_traceDestinationDir = new File(outputDir.getPath() + "/" + OUTPUT_TRACES_SUBDIR);
          if (!m_traceDestinationDir.isDirectory()) {
            log.warn("Output dir name does not correspond to an existing directory : " + m_traceDestinationDir);
            m_isConfigurationOkay = false;
          }
          else if (m_traceDestinationDir.getAbsolutePath().length() > MAX_SIZE) {
            log.warn("Output dir name already too long - cannot move the hosttraces there...");
            m_isConfigurationOkay = false;
          }
        }
      }
    }
  }

  /**
   * No modification to the input; but cleanup of old host traces here, which
   * are moved somewhere else.
   */
  @Override
  public String processInput(Stack<String> previousOutput, String input, Node config) {
    init(config);
    if (m_isConfigurationOkay) {
      moveTracesTo(m_oldTracesSubdir);
    }
    return input;
  }

  private void moveTracesTo(File destinationDirectory) {
    List<String> traceFileList = FileUtils.getFilesInDirWithSuffix(m_serverLogDir.getAbsolutePath(), ".xml");
    traceFileList.addAll(FileUtils.getFilesInDirWithSuffix(m_serverLogDir.getAbsolutePath(), ".a2c"));
    boolean needApiProxySubdir = traceFileList.addAll(FileUtils.getFilesInDirWithSuffix(m_serverLogDir
        .getAbsolutePath() +
        "/" + A2C_ULTIMATE_SUBDIR, A2C_ULTIMATE_SUBDIR + "/", ".a2c"));
    if (needApiProxySubdir) {
      File apiProxyBackupSubdir = new File(destinationDirectory.getPath() + "/" + A2C_ULTIMATE_SUBDIR);
      if (!apiProxyBackupSubdir.exists()) {
        apiProxyBackupSubdir.mkdir();
      }
    }
    String aTraceFileName;
    File aTraceFile;
    File aTraceMovedFile;
    for (Iterator<String> traceFileIter = traceFileList.iterator(); traceFileIter.hasNext();) {
      aTraceFileName = traceFileIter.next();

      aTraceFile = new File(m_serverLogDir.getPath() + "/" + aTraceFileName);
      aTraceMovedFile = new File(destinationDirectory.getPath() + "/" + aTraceFileName);
      aTraceFile.renameTo(aTraceMovedFile);
    }
  }

  /**
   * Copy the hosttraces to an output directory
   */
  @Override
  public void processOutput(String input, Node config, Shooter shooter) throws FatalException {
    init(config);
    if (m_isConfigurationOkay) {
      List<String> traceFileList = FileUtils.getFilesInDirWithSuffix(m_serverLogDir.getAbsolutePath(), ".xml");
      traceFileList.addAll(FileUtils.getFilesInDirWithSuffix(m_serverLogDir.getAbsolutePath(), ".a2c"));
      boolean needApiProxySubdir = traceFileList.addAll(FileUtils.getFilesInDirWithSuffix(m_serverLogDir
          .getAbsolutePath() + "/" + A2C_ULTIMATE_SUBDIR, A2C_ULTIMATE_SUBDIR + "/", ".a2c"));
      if (needApiProxySubdir) {
        File apiProxySubdir = new File(m_traceDestinationDir.getPath() + "/" + A2C_ULTIMATE_SUBDIR);
        if (!apiProxySubdir.exists()) {
          apiProxySubdir.mkdir();
        }
      }
      String aTraceFileName;
      File aTraceFile;
      File aTraceCopiedFile;
      if (traceFileList.size() > 0) {
        log.info("hosttraces will be copied in " + m_traceDestinationDir);
      }
      for (Iterator<String> traceFileIter = traceFileList.iterator(); traceFileIter.hasNext();) {
        aTraceFileName = traceFileIter.next();
        log.info("copied " + aTraceFileName);
        aTraceFile = new File(m_serverLogDir.getPath() + "/" + aTraceFileName);
        aTraceCopiedFile = new File(m_traceDestinationDir.getPath() + "/" + aTraceFileName);
        aTraceFile.renameTo(aTraceCopiedFile);
        // Post-processing of the copied files
        if (aTraceFileName.endsWith(".xml")) {
          String traceFileContent;
          try {
            // indent the content
            traceFileContent = FileUtils.readFromFileWithEncoding((aTraceCopiedFile.getPath()), null);
            // checkSizes(traceFileContent, verbNamesToCheckInXmlTraces);
            FileUtils
                .writeDataToFile(Dom4jUtils.getTidyXml(traceFileContent, null), aTraceCopiedFile.getAbsolutePath());

            // print the cryptic request found if any
            // traceFileContent = FileUtils.readDataFromFile(aTraceCopiedFile);
            // dumpCrypticRequestResponse(traceFileContent);

            // processHostTraceValidation(traceFileContent, config);
          }
          catch (IOException e) {
            log.error("Could not log trace sizes for file '" + aTraceCopiedFile + "'");
          }
          catch (TransformerException e) {
            log.error("Could not log trace sizes for file '" + aTraceCopiedFile + "'");
          }
          catch (TransformerFactoryConfigurationError e) {
            log.error("Could not load trasnformer factory for file '" + aTraceCopiedFile + "'");
          }
        }
      }
    }
  }

  /**
   * Creates <code>Node</code> object representation of xml element like:
   * '<RetrieveHostTraces tracedir="d:/java/bea/domains/mydomain/myserver/logs"
   * backuptracesubdir="backupTraces"/>'.
   */
  public static Node createRetrieveHostTracesServiceNode(Document document, String tracesDir, String backupSubDirName) {
    Node retrieveHostTracesNode = document.createElement("RetrieveHostTraces");
    SoapshooterScenario.addAttributeToNode(retrieveHostTracesNode, TRACE_DIR_KEY, tracesDir);
    SoapshooterScenario.addAttributeToNode(retrieveHostTracesNode, TRACE_BACKUP_SUBDIR_KEY, backupSubDirName);
    return retrieveHostTracesNode;
  }

}
